﻿using System;
using System.Collections.Concurrent;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace NahidaProject4CSharp.Generic
{
	/// <summary>
	/// 日志级别枚举
	/// </summary>
	public enum LogLevel { Debug = 0, Info = 1, Warn = 2, Error = 3, Fatal = 4 }

	/// <summary>
	/// 功能全面的日志类
	/// </summary>
	public class Logger : IDisposable
	{
		#region 字段和属性

		private static readonly Lazy<Logger> _instance = new(() => new Logger());
		public static Logger Instance => _instance.Value;

		private readonly string _logDirectory;
		private readonly string _logFileName;
		private readonly LogLevel _minLogLevel;
		private readonly bool _enableConsoleOutput;
		private readonly long _maxFileSize;
		private readonly int _maxBackupFiles;
		private readonly bool _enableAsync;

		private readonly ConcurrentQueue<LogEntry> _logQueue;
		private readonly CancellationTokenSource _cancellationTokenSource;
		private readonly Task _logTask;
		private readonly object _fileLock = new();
		private readonly object _consoleLock = new();

		private StreamWriter _currentWriter;
		private string _currentFilePath;
		private long _currentFileSize;

		#endregion

		#region 构造函数和初始化

		/// <summary>
		/// 私有构造函数（单例模式）
		/// </summary>
		private Logger()
		{
			// 默认配置
			_logDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs");
			_logFileName = "Logger.log";
			_minLogLevel = LogLevel.Info;
			_enableConsoleOutput = true;
			_maxFileSize = 10 * 1024 * 1024; // 10MB
			_maxBackupFiles = 5;
			_enableAsync = true;

			Initialize();
		}

		/// <summary>
		/// 带参数的构造函数
		/// </summary>
		public Logger(
			string logDirectory = null,
			string logFileName = "Logger.log",
			LogLevel minLogLevel = LogLevel.Info,
			bool enableConsoleOutput = true,
			long maxFileSize = 10485760, // 10MB
			int maxBackupFiles = 5,
			bool enableAsync = true)
		{
			_logDirectory = logDirectory ?? Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs");
			_logFileName = logFileName;
			_minLogLevel = minLogLevel;
			_enableConsoleOutput = enableConsoleOutput;
			_maxFileSize = maxFileSize;
			_maxBackupFiles = maxBackupFiles;
			_enableAsync = enableAsync;

			if (_enableAsync)
			{
				_logQueue = new ConcurrentQueue<LogEntry>();
				_cancellationTokenSource = new CancellationTokenSource();
				_logTask = Task.Run(ProcessLogQueue, _cancellationTokenSource.Token);
			}

			Initialize();
		}

		/// <summary>
		/// 初始化日志系统
		/// </summary>
		private void Initialize()
		{
			// 确保日志目录存在
			if (!Directory.Exists(_logDirectory))
			{
				Directory.CreateDirectory(_logDirectory);
			}

			// 初始化当前日志文件
			CreateNewLogFile();
		}

		#endregion

		#region 公共日志方法

		/// <summary>
		/// 记录调试日志
		/// </summary>
		public void Debug(string message, Exception exception = null)
		{
			Log(LogLevel.Debug, message, exception);
		}

		/// <summary>
		/// 记录信息日志
		/// </summary>
		public void Information(string message, Exception exception = null)
		{
			Log(LogLevel.Info, message, exception);
		}

		/// <summary>
		/// 记录警告日志
		/// </summary>
		public void Warning(string message, Exception exception = null)
		{
			Log(LogLevel.Warn, message, exception);
		}

		/// <summary>
		/// 记录错误日志
		/// </summary>
		public void Error(string message, Exception exception = null)
		{
			Log(LogLevel.Error, message, exception);
		}

		/// <summary>
		/// 记录致命错误日志
		/// </summary>
		public void Fatal(string message, Exception exception = null)
		{
			Log(LogLevel.Fatal, message, exception);
		}

		/// <summary>
		/// 通用日志记录方法
		/// </summary>
		public void Log(LogLevel level, string message, Exception exception = null)
		{
			// 检查日志级别
			if (level < _minLogLevel)
				return;

			var logEntry = new LogEntry
			{
				Timestamp = DateTime.Now,
				Level = level,
				Message = message,
				Exception = exception
			};

			if (_enableAsync)
			{
				_logQueue.Enqueue(logEntry);
			}
			else
			{
				WriteLogEntry(logEntry);
			}
		}

		#endregion

		#region 私有方法

		/// <summary>
		/// 异步处理日志队列
		/// </summary>
		private async Task ProcessLogQueue()
		{
			while (!_cancellationTokenSource.Token.IsCancellationRequested)
			{
				if (_logQueue.TryDequeue(out var logEntry))
				{
					WriteLogEntry(logEntry);
				}
				else
				{
					await Task.Delay(10, _cancellationTokenSource.Token);
				}
			}

			// 处理剩余的日志条目
			while (_logQueue.TryDequeue(out var logEntry))
			{
				WriteLogEntry(logEntry);
			}
		}

		/// <summary>
		/// 写入日志条目
		/// </summary>
		private void WriteLogEntry(LogEntry logEntry)
		{
			try
			{
				var logMessage = FormatLogMessage(logEntry);

				// 写入文件
				WriteToFile(logMessage);

				// 写入控制台
				if (_enableConsoleOutput)
				{
					WriteToConsole(logEntry.Level, logMessage);
				}
			}
			catch (Exception ex)
			{
				// 如果日志系统本身出错，避免递归调用
				Console.WriteLine($"Logger error: {ex.Message}");
			}
		}

		/// <summary>
		/// 格式化日志消息
		/// </summary>
		private string FormatLogMessage(LogEntry logEntry)
		{
			var sb = new StringBuilder();
			sb.Append($"[{logEntry.Timestamp:yyyy-MM-dd HH:mm:ss.fff}]");
			sb.Append($" [{logEntry.Level.ToString().ToUpper()}]");
			sb.Append($" {logEntry.Message}");

			if (logEntry.Exception != null)
			{
				sb.AppendLine();
				sb.Append($"Exception: {logEntry.Exception}");
			}

			return sb.ToString();
		}

		/// <summary>
		/// 写入文件
		/// </summary>
		private void WriteToFile(string message)
		{
			lock (_fileLock)
			{
				try
				{
					// 检查是否需要轮转日志文件
					if (_currentFileSize >= _maxFileSize)
					{
						RotateLogFile();
					}

					// 写入日志
					var messageBytes = Encoding.UTF8.GetBytes(message + Environment.NewLine);
					_currentWriter.Write(message);
					_currentWriter.WriteLine();
					_currentWriter.Flush();

					_currentFileSize += messageBytes.Length;
				}
				catch (Exception ex)
				{
					Console.WriteLine($"Failed to write to log file: {ex.Message}");
				}
			}
		}

		/// <summary>
		/// 写入控制台
		/// </summary>
		private void WriteToConsole(LogLevel level, string message)
		{
			lock (_consoleLock)
			{
				var originalColor = Console.ForegroundColor;

				try
				{
					Console.ForegroundColor = level switch
					{
						LogLevel.Debug => ConsoleColor.Gray,
						LogLevel.Info => ConsoleColor.White,
						LogLevel.Warn => ConsoleColor.Yellow,
						LogLevel.Error => ConsoleColor.Red,
						LogLevel.Fatal => ConsoleColor.Magenta,
						_ => ConsoleColor.White
					};

					Console.WriteLine(message);
				}
				finally
				{
					Console.ForegroundColor = originalColor;
				}
			}
		}

		/// <summary>
		/// 创建新的日志文件
		/// </summary>
		private void CreateNewLogFile()
		{
			lock (_fileLock)
			{
				try
				{
					_currentWriter?.Close();
					_currentFilePath = Path.Combine(_logDirectory, _logFileName);
					_currentWriter = new StreamWriter(_currentFilePath, true, Encoding.UTF8);
					_currentFileSize = new FileInfo(_currentFilePath).Length;
				}
				catch (Exception ex)
				{
					Console.WriteLine($"Failed to create log file: {ex.Message}");
				}
			}
		}

		/// <summary>
		/// 轮转日志文件
		/// </summary>
		private void RotateLogFile()
		{
			lock (_fileLock)
			{
				try
				{
					_currentWriter?.Close();

					// 删除最旧的备份文件
					var oldestBackup = Path.Combine(_logDirectory, $"{_logFileName}.{_maxBackupFiles}");
					if (File.Exists(oldestBackup))
					{
						File.Delete(oldestBackup);
					}

					// 重命名备份文件
					for (int i = _maxBackupFiles - 1; i >= 1; i--)
					{
						var oldFile = Path.Combine(_logDirectory, $"{_logFileName}.{i}");
						var newFile = Path.Combine(_logDirectory, $"{_logFileName}.{i + 1}");

						if (File.Exists(oldFile))
						{
							if (File.Exists(newFile))
								File.Delete(newFile);
							File.Move(oldFile, newFile);
						}
					}

					// 重命名当前日志文件
					var backupFile = Path.Combine(_logDirectory, $"{_logFileName}.1");
					if (File.Exists(backupFile))
						File.Delete(backupFile);
					File.Move(_currentFilePath, backupFile);

					// 创建新的日志文件
					CreateNewLogFile();
				}
				catch (Exception ex)
				{
					Console.WriteLine($"Failed to rotate log file: {ex.Message}");
				}
			}
		}

		#endregion

		#region IDisposable 实现

		/// <summary>
		/// 释放资源
		/// </summary>
		public void Dispose()
		{
			Dispose(true);
			GC.SuppressFinalize(this);
		}

		/// <summary>
		/// 释放资源
		/// </summary>
		protected virtual void Dispose(bool disposing)
		{
			if (disposing)
			{
				_cancellationTokenSource?.Cancel();
				_logTask?.Wait(1000); // 等待最多1秒

				lock (_fileLock)
				{
					_currentWriter?.Close();
					_currentWriter?.Dispose();
				}

				_cancellationTokenSource?.Dispose();
			}
		}

		#endregion
	}

	/// <summary>
	/// 日志条目类
	/// </summary>
	internal class LogEntry
	{
		public DateTime Timestamp { get; set; }
		public LogLevel Level { get; set; }
		public string Message { get; set; }
		public Exception Exception { get; set; }
	}
}
